package org.redmagic.service.dao;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.redmagic.domain.Property;
import org.redmagic.service.utils.MongoProperties;
import org.redmagic.service.utils.MongoUtils;

import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;

public class MongoDbDao implements MagicDao {

	private static final Log LOG = LogFactory.getLog(MongoDbDao.class);
	
	private final DBCollection properties;
	private final DBObject fields;
	
	public MongoDbDao(Mongo mongo, String databaseName, String collectionName) {		
		DB database = mongo.getDB(databaseName);
		this.properties = database.getCollection(collectionName);
		this.fields = new BasicDBObject(MongoProperties.ID, 0);
		this.fields.put(MongoProperties.VALUE_KEY, 1);
	}
	
	@Override
	public List<Property> getAllProperties() {
		
		List<Property> properties = new ArrayList<Property>();
		LOG.info("Getting all properties");

		DBObject query = new BasicDBObject();
		DBCursor dbResults = this.properties.find(query);
		for (DBObject result : dbResults) {
			
			BasicDBObject id = (BasicDBObject) result.get(MongoProperties.ID);
			String base = id.getString(MongoProperties.BASE);
			List<String> tags = Lists.newArrayList(id.getString(MongoProperties.TAGS_KEY));
			String value = (String) result.get(MongoProperties.VALUE_KEY);
			
			properties.add(new Property(base, tags, value));
		}
		
		return properties;
	}
	
	@Override
	public synchronized Optional<String> getProperty(String base, List<String> tags, String user) {
		
		LOG.info("Looking for property: " + base + ", with tags: " + tags);
		
		DBObject query = MongoUtils.getQuery(base, tags);
		DBObject dbResult = this.properties.findOne(query, fields);
		
		String value = null;
		if (dbResult != null) {
			value = (String) dbResult.get(MongoProperties.VALUE_KEY);
			this.properties.update(query, MongoUtils.getAccessObject(user));
		}
		
		LOG.info("Result: " + value);
		
		return Optional.fromNullable(value);
	}

	@Override
	public boolean createProperty(Property createOrUpdateProperty, String user) {
		DBObject insertObject = MongoUtils.getInsertObject(createOrUpdateProperty, user);
		this.properties.insert(insertObject, WriteConcern.SAFE);
		return true;
	}

	@Override
	public boolean updateProperty(Property property, String user) {
		DBObject queryObject = MongoUtils.getQuery(property);
		DBObject updateObject = MongoUtils.getUpdateObject(property, user);
		
		LOG.info("QueryObject: " + queryObject);
		LOG.info("UpdateObject: " + updateObject);
		
		this.properties.update(queryObject, updateObject);
		return true;
	}
}
